<?php
###############   COPYLEFT GPLv3 LICENSE   ###############
##
## JFX Version 0.2.7
## Website Management Software
## www.jfxcms.com
##
## Copyright 2009 GPLv3 - http://www.opensource.org/licenses/gpl-3.0.html
##
## Anthony Gallon
## oi_antz@hotmail.com
##
## Permission is hereby granted to any person having a copy of this software
## to freely use and modify as required so long as the copyright notices
## and branding remain intact.
##
## Full license details available at http://www.jfxcms.com/license
##
###############   COPYLEFT GPLv3 LICENSE   ###############

/**
 *  Antz First ever DB class!
 *  Provides handy functions for common tasks to MYSQL databases
 */ 

class JFX_Db
{
    private $conn;
    private $res;
    private $showErrors;
    private $debug;
    private $showOutput;
    
    public function __construct($host, $username, $pass, $dbName, $showErrors=false)
    {
    
        if(false === ($this->conn = mysql_connect($host, $username, $pass, true))){
            // error connecting
            //echo $host.' '.$username.' '.$pass.'<br />';
            return false;
        };
        $this->dbName = $dbName;
        $this->showErrors($showErrors);
        $this->showOutput(false);
        return $this->switchDb($dbName);
        
    }
    
    /**
     *  Turn errors on or off
     */         
    public function showErrors($bool)
    {
        $this->showErrors = ($bool===true || $bool===false) ? $bool : false;
    }
    public function showOutput($bool)
    {
        $this->showOutput = ($bool===true || $bool===false) ? $bool : false;
    }

    public function debug($bool)
    {
        $this->debug = ($bool===true || $bool === false) ? $bool : false;
    }
    
    /**
     *  Select another DB
     */         
    public function switchDb($dbName)
    {
        if(false===(mysql_select_db($dbName, $this->conn))){
            if($this->showErrors){
                echo 'error selecting database: '.$dbName.'<br />';
            };
            return false;
        };
        return true;
    }
    
    public static function stripSlashes($mixed)
    {
        if(is_array($mixed)){
            foreach($mixed as $k=>$v){
                $mixed[$k] = JFX_Db::stripSlashes($v);
            };
        }else{

//            $mixed = stripslashes($mixed);
        };
        return $mixed;
    }
    
    /**
     *  Returns an escaped version. Make sure you escape everything you get from a user
     */         
    public function makeSafe($text)
    {
        if(is_array($text)){
            foreach($text as $k=>&$v){
                $v = $this->makeSafe($v);
            };
        }else{
            return mysql_real_escape_string($text, $this->conn);
        };
    }
    
    public function escape($text){
        return $this->makeSafe($text);
    }
    
    /**
     *  Strips any unacceptable characters, leaving only character that are safe for keys
     */
    public function makeSafeKey($text)
    {
        return preg_replace('/[^0-9a-zA-Z\-_]/', '', $text);
    }         
    
    
    /**
     *  Number of rows that are in a result set
     */         
    public function numRows()
    {
        return @mysql_num_rows($this->res);
    }
    
    /**
     *  Number of rows that were affected by the last query
     */         
    public function affectedRows()
    {
        return @mysql_affected_rows($this->conn);
    }
    
    public function fetchRow($q)
    {
        if(false===$this->query($q))return false;
        return $this->_fetchRow();
    }
    
    public function select()
    {
        return new JFX_Db_Select;
    }
    
    public function delete($tablename, $where)
   { // BEGIN function delete
   	    $this->query('DELETE FROM '.$tablename. ' WHERE '.$where);
   } // END function delete
    
    public function query($q)
    {
        if(is_object($q) && $q instanceof JFX_Db_Select) $q = (string) $q;
        if(false === ($this->res = mysql_query($q, $this->conn)) && $this->showErrors){
            JFX::addError(mysql_error($this->conn));
            JFX::addError($q.';');
            try{
                throw new JFX_Exception(mysql_error($this->conn));
            } catch (Exception $e){
                
            } 
            return false;
        };
        if($this->debug && strtoupper(substr(trim($q), 0, 6))=='SELECT'){
            global $JFXDBDebug;
            $this->debug(false);
            $oldRes = $this->res;
            //echo $q.'<br />';
            $count = count($JFXDBDebug);
            $JFXDBDebug[$count] = $this->fetchRow('EXPLAIN '.$q);
            $JFXDBDebug[$count]['query'] = 'EXPLAIN '.$q;
            $this->res = $oldRes;
            $this->debug(true);
        }
        if($this->showOutput) echo $q.'<br />';
        return true;
    }
    
    private function _fetchRow()
    {
        return $this->stripSlashes(@mysql_fetch_assoc($this->res));
    }
    
    public function fetchAll($q)
    {
        if(false===$this->query($q))return false;
        $arr = array();
        while($r = $this->_fetchRow()){
            $arr[] = $r;
        };
        return $arr;
    }
    
    /**
     *  Inserts a new row in the db, returns insertId or false
     */         
    public function insert($table, $pairs)
    {
        $keys = array();
        $values = array();
        foreach($pairs as $k=>$v){
            $keys[] = $k;
            $values[] = $this->escape($v);
        };
        $keys = implode(', ', $keys);
        $values = implode("','", $values);
        $q = "INSERT INTO {$table} ({$keys}) VALUES ('".$values."')";
        if(false === ($this->query($q)) && $this->showErrors) return false;
        
        return mysql_insert_id($this->conn);
    }
    
    
    public function update($tableName, $pairs, $where)
    {
        $qs = array();
        foreach($pairs as $k=>$v){
            $qs[] = $k." = '".mysql_real_escape_string($v, $this->conn)."'";
        };
        $q = "UPDATE {$tableName} SET ".implode(',', $qs)." WHERE {$where}";
        $this->query($q);
    }
    
    

    /**
     *  Count how many rows match a condition. Useful for checking if a result exists
     *  EG:
     *     if($DB->countRows('users', array("id = '$userId'")) > 0){
     *         // we know there is a user with the corresponding id
     *     }     
     */
             
    public function countRows($tableName, $params)
    {
        return $this->oneValue($tableName, 'COUNT(*)', $params);
    }

    /**
     *  Allows you to get 1 value from the db in 1 step:
     *   EG:
     *     $title = $DB->oneValue('tableName', 'title', array("id = '$topicId'"));
     */
    public function oneValue($tableName, $field, $params)
    {
        $q = "SELECT {$field} FROM {$tableName} ";
     
        if(is_array($params)) $params = implode(' AND ', $params);
        if($params != ''){
            $q .= ' WHERE '.$params;
        };
        $res = $this->fetchRow($q);
        if($res === false) return false;
        return $res[$field];
    }               
    
    /**
     *  Allows one field to be incremented 
     */         
    public function incrementField($table, $field, $where, $amount=1)
    {
        $where = implode(' AND ', $where);
        $q = "UPDATE {$table} SET {$field} = ({$field} + {$amount}) WHERE {$where}";
        $this->query($q);
    }
    
}
